// func_muteks.cpp - Marcin Abram
// Systemy operacyjne - Krakow, 30 maj 2008 r.
//
// Funkcje biblioteczne ulatwiajace uzywanie muteksow

#ifndef _REENTRANT
#define _REENTRANT
#endif // uwaga, musi stac przed wszystkimi #include
#include<cstdio>
#include<stdlib.h>
#include<pthread.h>
#include<iostream>
#include<errno.h>
#include"thread2.h"
using namespace std;

// tworzenie watku z standardowymi ustawieniami. Funkcja start_fun pobiera
// argument jako liczbę naturalna (int)
pthread_t* threadCreate(void*(*start_fun)(void*), void *arg)
{
	pthread_t* id = new(pthread_t);
	int stan = pthread_create(id, NULL, start_fun, arg);
	// Komunikaty niepowodzen przy tworzeniu nowego watku (gdy stan !=0)
	if(stan)
	{
		switch(stan)
		{
			case EAGAIN:
				cerr << "BLAD: zostal przekroczony systemowy limit liczby watkow";
				cerr << " lub procesow LWP." << endl; break;
			case ENOMEM:
				cerr << "BLAD: brak pamieci do utworzenia nowego watku" << endl; break;
			case EINVAL:
				cerr << "BLAD: nieprawidlowa wartosc argumentu attr," << endl;
				cerr << "      tj. 2. argumentu funkcji pthread_create" << endl; break;
			default:
				cerr << "BLAD " << stan << ": zwiazany z tworzeniem nowego watku" << endl;
		}
		exit(EXIT_FAILURE);
	}
	return id;
}
// koniec watek_new

void threadDestroy(void *status)
{
	pthread_exit(status);
	return;
}
// koniec watek_zakoncz

// czekanie na watek (i ignorowanie informacji o stanie koncowym watku)
void threadJoin(pthread_t id, void** status)
{
	int stan = pthread_join(id, status);
	if(stan != 0)
	{
		cerr << "BLAD " << stan << ": zwiazany z czekaniem na zakonczenie watku";
		cerr << " (z jednoczesnym ignorowaniem jego stanu)." << endl;
		exit(EXIT_FAILURE);
	}
	return;
}
// koniec watek_czekaj

// czekanie na watek (i ignorowanie informacji o stanie koncowym watku)
void threadJoinIgn(pthread_t id)
{
	int stan = pthread_join(id, NULL);
	if(stan != 0)
	{
		cerr << "BLAD " << stan << ": zwiazany z czekaniem na zakonczenie watku";
		cerr << " (z jednoczesnym ignorowaniem jego stanu)." << endl;
		exit(EXIT_FAILURE);
	}
	return;
}
// koniec watek_czekaj_Ign

void threadDetach(pthread_t id)
{
	if(pthread_detach(id) != 0)
	{
		cerr << "BLAD: z odlaczaniem (detach) watku." << endl;
		exit(EXIT_FAILURE);
	}
	return;
}
// koniec watek_odlacz

// tworzenie domyslnego, wewnatrzwatkowego mutexu (jest on automatycznie otwarty)
pthread_mutex_t* mutexNew()
{
	pthread_mutex_t* myMutex = new(pthread_mutex_t);
	int stan = pthread_mutex_init(myMutex, NULL);
	if(stan)
	{
		if(stan == EINVAL)
		{
			cerr << "BLAD: przy tworzeniu mutexu - nieodpowiednie argumenty";
			cerr << " funkcji pthread_mutex_init" << endl;
		}
		else
		{
			cerr << "BLAD " << stan << ": przy tworzeniu mutexu" << endl;
		}
		exit(EXIT_FAILURE);
	}
	return myMutex;
}
// koniec mutex_new

void mutexClose(pthread_mutex_t *wsk)
{
	if(pthread_mutex_lock(wsk))
	{
		cerr << "BLAD: z zamykaniem muteksu (funkcja pthread_mutex_lock)" << endl;
		exit(EXIT_FAILURE);
	}
	return;
}
// koniec mutex_zamknij

// blokujace otwarcie muteksu
void mutexOpenUnlock(pthread_mutex_t *wsk)
{
	if(pthread_mutex_unlock(wsk))
	{
		cerr << "BLAD: z otwieraniem muteksu (funkcja pthread_mutex_unlock)" << endl;
		exit(EXIT_FAILURE);
	}
	return;
}
// koniec mutex_otworz

void mutexOpenTrylock(pthread_mutex_t *wsk)
{
	if(pthread_mutex_trylock(wsk))
	{
		cerr << "BLAD: z otwieraniem (nieblokujacym) muteksu. (ptrhear_mutex_trylock)" << endl;
		exit(EXIT_FAILURE);
	}
	return;
}
// koniec mutex_otworz_NBlok

void mutexDestroy(pthread_mutex_t *wsk)
{
	if(pthread_mutex_destroy(wsk))
	{
		cerr << "BLAD: z zamykaniem muteksu. (pthread_mutex_destroy)" << endl;
		exit(EXIT_FAILURE);
	}
	// mutex na ktory wskazuje wsk tak naprawde stal sie jedynie niezainicjalizowany
	// nalezy go recznie usunac z pamieci
	delete(wsk);
	return;
}
// koniec mutexDestroy
